﻿// ReSharper disable InconsistentNaming

using System;
using System.Collections;
using System.Collections.Generic;
using Common;
using ImageProcessing.Matchers;
using ImageProcessing.Descriptors;
using ImageProcessing.Detectors;
using ImageProcessing.Common;
using NUnit.Framework;

namespace ImageProcessing.Tests.Matchers
{
    [TestFixture]
    public class HandlerNearestNeighbourTests
    {
        private List<InterestPoint> _usbObservedImage;
        private List<InterestPoint> _squareObservedImage;

        private List<InterestPoint> sqaureIP;
        private List<InterestPoint> usbIP;
        private readonly List<InterestPoint> allIP = new List<InterestPoint>();

        private HandlerNearestNeighbour _handlerNearestNeighbour;

        const string Square = "SQUARE";
        private TagInfo SquareId;
        const string Usb = "USB";
        private TagInfo UsbId;

        [TestFixtureSetUp]
        public void TestFixtureSetup()
        {
            SquareId = new TagInfo(Guid.NewGuid(), Square);
            UsbId = new TagInfo(Guid.NewGuid(), Usb);

            _usbObservedImage = GetInterestPoints("TestPics\\USB1.jpg", null);
            _squareObservedImage = GetInterestPoints("TestPics\\Square.jpg", null);

            sqaureIP = GetInterestPoints("TestPics\\Square.jpg", SquareId);
            usbIP = GetInterestPoints("TestPics\\USB1.jpg", UsbId);
            allIP.AddRange(usbIP);
            allIP.AddRange(sqaureIP);
        }

        [SetUp]
        public void Setup()
        {
            _handlerNearestNeighbour = new HandlerNearestNeighbour();
            _handlerNearestNeighbour.Train(allIP);
        }


        [Test]
        public void Classify_CheckPointsAgainstImage_True()
        {
            CheckFound(sqaureIP, SquareId, _squareObservedImage, _handlerNearestNeighbour, true);
            CheckFound(usbIP, UsbId, _usbObservedImage, _handlerNearestNeighbour, true);
        }

        [Test]
        public void Classify_CheckPointsAgainstAllImages_True()
        {
            CheckFound(sqaureIP, SquareId, _squareObservedImage, _handlerNearestNeighbour, true);
            CheckFound(usbIP, UsbId, _usbObservedImage, _handlerNearestNeighbour, true);
        }

        [Test]
        public void Classify_CheckPointsAgainstAllImages_False()
        {
            CheckFound(usbIP, UsbId, _squareObservedImage, _handlerNearestNeighbour, false);
            CheckFound(sqaureIP, SquareId, _usbObservedImage, _handlerNearestNeighbour, false);
        }

        [Test]
        public void Train_CheckForDoublePoints_Equal()
        {
            _handlerNearestNeighbour.Clear();

            var newPoints = _handlerNearestNeighbour.Train(sqaureIP);
            Assert.AreEqual(sqaureIP.Count, newPoints.Count);

            newPoints = _handlerNearestNeighbour.Train(sqaureIP);
            Assert.AreEqual(0, newPoints.Count);


        }

        [Test, Ignore("WIP")]
        public void Classify_CheckPointsAgainstCard1TemplateImages_False()
        {
            TagInfo tagInfo = new TagInfo(Guid.NewGuid(),"test");
            var card1Template = GetInterestPoints("TestPics\\Card1Template.jpg", tagInfo);
            _handlerNearestNeighbour.Train(card1Template);

            var card1ZoomedIn = GetInterestPoints("TestPics\\Card1ZoomedIn.jpg", null);
            CheckFound(card1Template, tagInfo, card1ZoomedIn, _handlerNearestNeighbour, true, false);

            var card1ZoomedOut = GetInterestPoints("TestPics\\Card1ZoomedOut.jpg", null);
            CheckFound(card1Template, tagInfo, card1ZoomedOut, _handlerNearestNeighbour, true, false);
        }



        private static void CheckFound(ICollection expectedImage, TagInfo tagInfo, IEnumerable<InterestPoint> observedImage, HandlerNearestNeighbour handlerNearestNeighbour, bool expected, bool checkExpected = true)
        {
            Dictionary<TagInfo, List<FeaturesFound>> classifiedResult = handlerNearestNeighbour.Classify(observedImage);
            Assert.IsTrue(classifiedResult.Count == 1);
            Assert.AreEqual(expected, classifiedResult.ContainsKey(tagInfo));

            if (checkExpected)
                CheckExpectedMatch(expectedImage, tagInfo, expected, classifiedResult);
        }

        private static void CheckExpectedMatch(ICollection expectedImage, TagInfo tagInfo, bool expected, IDictionary<TagInfo, List<FeaturesFound>> classifiedResult)
        {
            if (expected)
                Assert.IsTrue(classifiedResult[tagInfo].Count > expectedImage.Count * 0.95 && classifiedResult[tagInfo].Count < expectedImage.Count * 1.05);
        }

        private static List<InterestPoint> GetInterestPoints(string imageName, TagInfo tagInfo)
        {
            int height;
            int width;
            HelperMethods.GetImageDimensions(imageName, out width, out height);

            var iimage = new IntegralImage(width, height);

            var fastHessian = new FastHessian(0.0001f, 5, 2, width, height, iimage);
            var interestPoints = HelperMethods.GetPoints(imageName, fastHessian);


            SurfDescriptor.DecribeInterestPoints(interestPoints, false, false, iimage, tagInfo);

            return interestPoints;
        }
    }
}
